package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import com.iwhalecloud.citybrain.flow.platform.manager.application.ConvertUtil.FormProcessInstanceHandleRelConvertUtil;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ReadDoTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.FlowBaseDataHandleProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.ProcessInstanceHandleRelService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task.UserInfoHandleProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.CollectionUtil;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.TaskNodeAuthComponent;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpProcessInstanceHandleRelDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.CommentTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.HandleStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormProcessInstanceHandleRelDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormProcessInstanceHandleRelVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.model.NodeAuthVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowProcessInstanceHandleRelRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowTaskService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
　　* @description: 流程实例处理关系服务实现
　　* @author shenrm
　　* @date 2021/11/10 11:17
　　*/
@Service
public class ProcessInstanceHandleRelServiceImpl implements ProcessInstanceHandleRelService {

    private Logger logger  = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FlowProcessInstanceHandleRelRepository handleRelRepository;

    @Autowired
    private FlowBaseDataHandleProcessor flowBaseDataHandleProcessor;

    @Autowired
    private UserInfoHandleProcessor userInfoHandleProcessor;

    @Autowired
    private FlowTaskService flowTaskService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private TaskNodeAuthComponent taskNodeAuthComponent;

    @Override
    public ResponseResult dealReadDoData(HttpProcessInstanceHandleRelDto processInstanceHandleRelDto) {

        // 流程实例ID
        String processInstanceId = processInstanceHandleRelDto.getProcessInstanceId();

        // 解析阅办人员或其它关联信息
        Map<String, List<String>> dataMap = userInfoHandleProcessor.resolveReadDoUsers(processInstanceHandleRelDto);
        if(MapUtils.isEmpty(dataMap)) {
            return ResponseResult.fail(ErrorCode.PARAM_NOT_EXIST.errCode(), "阅办人或其它维度不能都为空");
        }

        // 阅办人ID集合
        List<String> readCopyTos = dataMap.get(ReadDoTypeEnum.STA.getCode());

        // 阅办人所属组织集合
        List<String> orgCodes = dataMap.get(ReadDoTypeEnum.ORG.getCode());

        // 阅办人所属角色集合
        List<String> roleCodes = dataMap.get(ReadDoTypeEnum.ROL.getCode());

        // 阅办人所属用户组集合
        List<String> groupCodes = dataMap.get(ReadDoTypeEnum.GROUP.getCode());

        // 阅办人所属岗位集合
        List<String> positionCodes = dataMap.get(ReadDoTypeEnum.POSITION.getCode());

        // 任务实例ID
        String taskId = processInstanceHandleRelDto.getTaskId();

        // 流程实例和任务实例不能同时为空
        if (StringUtils.isBlank(processInstanceId) && StringUtils.isBlank(taskId)) {
            return ResponseResult.fail(ErrorCode.PARAM_NOT_EXIST.errCode(), "processInstanceId和taskId不能都为空");
        }

        // 校验是否是当前责任人发起的阅办任务
        String sendUserCode = processInstanceHandleRelDto.getSendUserCode();
        if(StringUtils.isBlank(sendUserCode)) {
            return ResponseResult.fail(ErrorCode.PARAM_NOT_EXIST.errCode(), "sendUserCode不能都为空");
        }

        // 根据任务id和用户编码获取是否节点操作权限
        NodeAuthVo nodeAuthVo = taskNodeAuthComponent.getNodeAuthByTaskIdAndUserCode(taskId, sendUserCode);
        if(Objects.isNull(nodeAuthVo) || (Objects.nonNull(nodeAuthVo) && (Objects.isNull(nodeAuthVo.getReadHandle()) || !nodeAuthVo.getReadHandle()))) {
            return ResponseResult.fail(ErrorCode.NO_READ_DO_AUTH.errCode(),ErrorCode.NO_READ_DO_AUTH.errMessage());
        }

        // 任务实例是否存在
        if(StringUtils.isNotBlank(taskId)) {

            // 查询有效任务
            FlowTaskTraceVo flowTaskTraceVo = flowTaskService.getFlowTaskByTaskIdOrUserCode(taskId,sendUserCode);

            // 不存在时,返回提示
            if(Objects.isNull(flowTaskTraceVo)) {
                return ResponseResult.fail(ErrorCode.ONLY_TASK_RESPONSIBLE_START.errCode(), ErrorCode.ONLY_TASK_RESPONSIBLE_START.errMessage());
            }
        }

        // 校验流程实例是否存在
        if(StringUtils.isNotBlank(processInstanceId)) {
            boolean isExistProcessInstance = flowBaseDataHandleProcessor.isExistCheckProcessInstance(processInstanceId);
            if(!isExistProcessInstance) {
                return ResponseResult.fail(ErrorCode.PROCESS_INSTANCE_NOT_EXIST.errCode(), ErrorCode.PROCESS_INSTANCE_NOT_EXIST.errMessage());
            }
        }

        // 如果传的不是具体的人员,则需要解析对应的类型,例如：组织、角色、岗位或用户组
        List<UserInfo> userInfos = userInfoHandleProcessor.resolveUserInfoList(readCopyTos, orgCodes, roleCodes, positionCodes, groupCodes);

        // 用户信息不为空
        if(CollectionUtils.isNotEmpty(userInfos)) {

            // 类型转换
            List<String> readCopyToList = userInfos.stream().map(userInfo -> {
                return userInfo.getUserCode();
            }).collect(Collectors.toList());

            // 剔除自己
            List<String> deleteSendUserList = new ArrayList();

            // 检查自己不能给自己发送阅办,如果是自己,则删除自己,自己收不到这条阅办信息
            for (String readCopyTo : readCopyToList) {
                if(!Objects.equals(readCopyTo, sendUserCode)) {
                    deleteSendUserList.add(readCopyTo);
                }
            }

            // 先根据更新条件校验需要处理的阅办记录是否存在
            List<FormProcessInstanceHandleRelVo> rtList = handleRelRepository.selectByConditionNoPage(processInstanceId, taskId);
            if(CollectionUtils.isNotEmpty(rtList)) {

                // 类型转换
                List<String> checkUserList = rtList.stream().map(vo -> {
                    return vo.getHandlerId();
                }).collect(Collectors.toList());

                // 如果查到的所有记录大于或等于发起的人,说明是全部记录已存在
                if(checkUserList.containsAll(deleteSendUserList)) {
                    return ResponseResult.fail(ErrorCode.DATA_EXIST.errCode(), "按照传值条件查询数据已存在,无法进行阅办处理操作");
                }

                // 部分存在,则进行过滤处理
                // 如果一个taskId节点发送给一个例如组织,下面有2个人,张三和李四,张三已经收到了这个taskId的阅办信息,但李四是新的,则将张三剔除,只保留李四
                deleteSendUserList = CollectionUtil.listrem(deleteSendUserList, checkUserList);
            }

            // 阅办人员编码去重
            List<String> readDoUsers = deleteSendUserList.stream().distinct().collect(Collectors.toList());

            // 如果不存在,则直接插入阅办处理数据表中
            List<FormProcessInstanceHandleRelDto> relDtos = FormProcessInstanceHandleRelConvertUtil.convertToRequestDtoList(processInstanceHandleRelDto, readDoUsers);

            // 保存流程实例或任务实例与处理人(这里是阅办人)的关系信息
            try {
                handleRelRepository.batchInsertFlowFormProcessInstanceHandleRel(relDtos);
            } catch (Exception ex) {
                logger.error("存储阅办人关联信息时失败,流程实例ID:" + processInstanceId + ",任务实例ID: "+ taskId +",失败信息：" + ex.getMessage(), ex);
                return ResponseResult.fail(ErrorCode.SAVE_DATA_FAIL.errCode(), "存储阅办人关联信息时失败");
            }

            // 意见不为空时,则添加
            if (Objects.nonNull(processInstanceHandleRelDto.getComment())){
                taskService.addComment(taskId, processInstanceId, CommentTypeEnum.YB.getName(),processInstanceHandleRelDto.getComment());
            }
        }
        return ResponseResult.success();
    }

    /**
     * 更新阅办状态
     *
     * @param processInstanceHandleRelDto
     * @return
     */
    @Override
    public ResponseResult updateReadDoStatus(HttpProcessInstanceHandleRelDto processInstanceHandleRelDto) {
        // 流程实例ID集合
        List<String> processInstanceIds = processInstanceHandleRelDto.getProcessInstanceIds();

        // 阅办人ID
        String readCopyTo = processInstanceHandleRelDto.getReadCopyTo();

        // 任务实例ID集合
        List<String> taskIds = processInstanceHandleRelDto.getTaskIds();
        if (StringUtils.isBlank(readCopyTo)) {
            return ResponseResult.fail(ErrorCode.PARAM_NOT_EXIST.errCode(), "readCopyTo不能为空");
        }

        if (CollectionUtils.isEmpty(processInstanceIds) && CollectionUtils.isEmpty(taskIds)) {
            return ResponseResult.fail(ErrorCode.PARAM_NOT_EXIST.errCode(), "processInstanceIds和taskIds不能都为空");
        }

        // 阅办人
        List<String> readCopyTos = new ArrayList<>();
        readCopyTos.add(readCopyTo);
        // 先根据更新条件校验需要更新的阅办记录是否存在
        boolean isExist = handleRelRepository.isExistCheckData(readCopyTos, processInstanceIds, taskIds);
        if(!isExist) {
            return ResponseResult.fail(ErrorCode.NOT_EXIST.errCode(), "按照传值条件查询数据不存在,无法进行更新操作");
        }

        //标记为已读
        handleRelRepository.updateByExampleSelective(readCopyTo, taskIds, processInstanceIds, HandleStatusEnum.READ.getCode().intValue());
        return ResponseResult.success();
    }
}
